import { cloneDeep, omit } from "lodash";
import { diff, unpatch, patch } from "jsondiffpatch";
import useFileStore from "../store/files";

const initState = {}

export class History {
  diffs = [];
  index = 0;
  canvasData = {};
  constructor(canvas) {
    this.canvas = canvas;
    const canvasJson = this.canvas.toDatalessJSON([
      "id",
      "_customType",
      "perPixelTargetFind",
      "objectCaching",
    ]);
    this.canvasData = {
      ...omit(canvasJson, "objects"),
      objects: cloneDeep(canvasJson?.objects ?? []),
    };
  }
  saveState() {
    if (this.canvas) {
      this.diffs = this.diffs.slice(0, this.index);
      const canvasJson = this.canvas.toDatalessJSON([
        "id",
        "_customType",
        "perPixelTargetFind",
        "objectCaching",
      ]);
      const delta = diff(canvasJson, this.canvasData);
      this.diffs.push(delta);
      console.log("saveState diff:", delta);
      // More than 50 operations, remove initial state
      if (this.diffs.length > 50) {
        this.diffs.shift();
      } else {
        this.index++;
      }
      this.canvasData = {
        ...omit(canvasJson, "objects"),
        objects: cloneDeep(canvasJson?.objects ?? []),
      };
      useFileStore.getState().updateBoardData(canvasJson);
      //   const { files,currentId } = useFileStore.getState();
      //   const file = files?.find((item) => item?.id === currentId);
      //   console.log("file", file);
    }
  }

  undo() {
    const canvas = this.canvas;
    if (canvas && this.index > 0) {
      const delta = this.diffs[this.index - 1];
      this.index--;
      console.log("undo", delta);
      const canvasJson = patch(this.canvasData, delta);
      canvas.loadFromJSON(canvasJson, () => {
        //   handleCanvasJSONLoaded(canvas)
        canvas.requestRenderAll();
        useFileStore.getState().updateBoardData(canvasJson);
        this.canvasData = {
          ...omit(canvasJson, "objects"),
          objects: cloneDeep(canvasJson?.objects ?? []),
        };
      });
    }
  }
  redo() {
    const canvas = this.canvas;
    if (this.index < this.diffs.length && canvas) {
      const delta = this.diffs[this.index];
      this.index++;
      console.log("redo", delta);
      const canvasJson = unpatch(this.canvasData, delta);
      canvas.loadFromJSON(canvasJson, () => {
        //   handleCanvasJSONLoaded(canvas)
        canvas.requestRenderAll();
        useFileStore.getState().updateBoardData(canvasJson);
        this.canvasData = {
          ...omit(canvasJson, "objects"),
          objects: cloneDeep(canvasJson?.objects ?? []),
        };
      });
    }
  }
  clean() {
    this.canvas?.clear();
    this.index = 0;
    this.diffs = [];
    this.canvasData = {};
    useFileStore.getState().updateBoardData(initState);
  }

  initHistory() {
    const canvas = this.canvas;
    if (canvas) {
      const canvasJson =this.canvas.toDatalessJSON([
        "id",
        "_customType",
        "perPixelTargetFind",
        "objectCaching",
      ]);
      this.canvasData = canvasJson;
      this.index = 0;
      this.diffs = [];
    }
  }
}

// jsondiffpatch 是一个用于在 JSON 对象之间进行比较和应用变更的 JavaScript 库。这里是它提供的一些核心方法的概述：
// diff:
// diff 方法用于比较两个 JSON 对象，并生成一个表示它们之间差异的 delta 对象。这个 delta 对象详细记录了从原始对象转换到新对象所需的修改。
// patch:
// patch 方法用于将之前由 diff 生成的 delta 应用到一个 JSON 对象上。这使得您可以将存储或传输的 delta 应用回原始对象，重建修改后的版本。
// unpatch:
// unpatch 方法执行与 patch 相反的操作。它可以将一个已应用 delta 的对象恢复到其原始状态。这在需要撤销更改时非常有用。
// Delta:
// Delta 是 jsondiffpatch 中使用的术语，指的是表示两个对象之间差异的对象。Delta 对象包含了足够的信息来描述如何从一个对象转变到另一个对象，包括添加、删除、修改的详细指示。
